package com.spring.boot.config.security;

import com.spring.boot.filter.MyOncePerRequestFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

/**
 * @author 刘骄阳
 * 2021-07-13 20:09
 */
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    UserDetailsService service;
    @Resource
    RestAuthenticationEntryPoint entryPoint;
    @Resource
    RestfulAccessDeniedHandler handler;

    /**
     * 使用自定义的MyPasswordEncoder
     *
     * @return 对象
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new MyPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //通过实现类,自定义用户名和密码
        auth.userDetailsService(service).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //自定义到自己的编写登录页面
        http.formLogin()
                //登录页面设置,未认证跳转的接口
                .loginPage("/login")
                //登录访问路径,
                .loginProcessingUrl("/user/login")
                //认证成功跳转路径
                .defaultSuccessUrl("/test/add").permitAll()
                .and().authorizeRequests()
                //定义不需要认证就能访问的路径
                .antMatchers("/test/public/**", "/", "/test/returnError", "/test/getToken", "/test/hello", "/user/login", "/root/rootLogin", "/js/**", "/css/**", "/files/**", "/images/").permitAll()
                //设置含有指定权限才能访问的路径
                //.antMatchers("/test/add").hasAuthority("1")
                //设置含有指定权限的其中一个才能访问
                //.antMatchers("/test/insert").hasAnyAuthority("2,3")
                //.antMatchers("/root/*").hasAnyAuthority("4")
                //设置含有指定角色才能访问的路径,源码中会在角色的前面加上ROLE_,例:ROLE_root
                //.antMatchers("/root/*").hasRole("管理员")
                //设置其他的路径需要认证才能访问
                .anyRequest().authenticated()
                //关闭csrf防护
                .and().csrf().disable()
                //使用filter过滤器
                .addFilterBefore(new MyOncePerRequestFilter(), UsernamePasswordAuthenticationFilter.class)
                //配置没有权限与没有登录返回值
                .exceptionHandling().accessDeniedHandler(handler).authenticationEntryPoint(entryPoint)
        ;
    }

    /**
     * 如果不重写会报错
     * Consider defining a bean of type 'org.springframework.security.authentication.AuthenticationManager' in your configuration.
     *
     * @return 结果
     * @throws Exception 异常
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
